// HSS.Logging.Management.LogViewer.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       LogViewer.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/04/2010
// ----------------------------------------------------------------------------
namespace HSS.Logging.Management
{
	#region Using Directives
	using System;
	using System.ComponentModel;
	using System.Diagnostics;
	using System.IO;
	using System.Text;
	using System.Windows.Forms;
	using HSS.Forms;
	using System.Security.Permissions;
	#endregion

	#region LogViewer
	/// <summary>
	/// The LogViewer
	/// </summary>
	public sealed partial class LogViewer : Form
	{
		#region Static Methods
		/// <summary>
		/// Runs the LogViewer as a stand alone application
		/// </summary>
		[STAThread()]
#if !DEBUG
		[PrincipalPermissionAttribute(SecurityAction.Demand, Role = "Administrators")]
#endif
		public static void Run(string[] args)
		{
			using (AppContext<LogViewer> ctx = new AppContext<LogViewer>())
				ctx.Run(args, InitApp);
		}
		private static LogViewer InitApp(string[] args, AppContext<LogViewer> ctx)
		{
			ctx.ShowError += new EventHandler<SendExceptionEventArgs>(App_ShowError);
			ctx.SendException += new EventHandler<SendExceptionEventArgs>(App_SendException);

			var viewer = new LogViewer();

			if (!viewer.available)
			{
				LogViewer.ShowUnableToStartError(viewer.notAvailableError);
				return null;
			}

			if (args.Length > 0)
				viewer.cmdLineFile = args[0];

			if (!viewer.InitializeUI())
				return null;

			return viewer;
		}
		private static void App_ShowError(object sender, SendExceptionEventArgs e)
		{
			MessageBox.Show(e.UnhandledException.ToString(), "Exception Message", MessageBoxButtons.OK, MessageBoxIcon.Warning);
		}
		private static void App_SendException(object sender, SendExceptionEventArgs e)
		{
			if (e.SendException)
				SendException(e.UnhandledException);

			if (e.RestartApp)
				Application.Restart();
		}
		private static void SendException(Exception ex)
		{
			SendException(ex.ToString());
		}
		private static void SendException(string message)
		{
			System.Threading.ThreadPool.QueueUserWorkItem(SendException, message);
		}
		private static void SendException(object objMessage)
		{
			try
			{
				var builder = new StringBuilder(objMessage.ToString());
				builder.AppendLine();
				builder.AppendLine();
				AppContext<LogViewer>.AppendAppContextInfo(builder);
				builder.AppendLine();
				builder.AppendLine();
				AppContext<LogViewer>.AppendEnvironmentInfo(builder);
				var subject = Application.ProductName + ": " + HSS.Logging.Management.Resources.supportSubject;
				var msg = new System.Net.Mail.MailMessage(HSS.Logging.Management.Resources.suppportEmail, HSS.Logging.Management.Resources.suppportEmail, subject, builder.ToString());
				HSS.Net.Mail.SmtpClient.SendEmail(msg);
			}
			catch { }
		}
		private static void ShowUnableToStartError(string ErrorMsg)
		{
			MessageBox.Show(ErrorMsg, HSS.Logging.Management.Resources.msgUnableToStartCaption, MessageBoxButtons.OK, MessageBoxIcon.Warning);
		}

		/// <summary>
		/// Show the LogViewer
		/// </summary>
		/// <param name="ShowAsDialog">Indicate if it should be shown as a Form Dialog</param>
		/// <param name="owner">The owning form</param>
		public static void Show(bool ShowAsDialog, IWin32Window owner)
		{
			using (var viewer = new LogViewer())
			{
				if (!viewer.available)
				{
					LogViewer.ShowUnableToStartError(viewer.notAvailableError);
					return;
				}
				viewer.InitializeUI();
				if (ShowAsDialog)
					viewer.ShowDialog(owner);
				else
					viewer.Show(owner);
			}
		}
		#endregion

		#region Fields
		LogViewerListView logViewDoc;
		LogViewerListView activeDoc;
		LogItemViewer logItemView;
		LogAttachmentViewer logAttachView;
		SqlLogReader logReader;
		const string currentLog = "Current Log";
		string cmdLineFile;
		string notAvailableError = string.Empty;
		bool available;
		#endregion

		#region Constructor
		/// <summary>
		/// Constructor
		/// </summary>
		private LogViewer()
		{
			this.InitializeComponent();

			this.logReader = new SqlLogReader();
			if (!this.logReader.InitializeLogReader())
			{
				notAvailableError = HSS.Logging.Management.Resources.msgLogUnavailable;
				return;
			}

			available = true;
		}
		private void LogViewer_Shown(object sender, EventArgs e)
		{
			if (string.IsNullOrEmpty(cmdLineFile))
			{
				this.mnuLog_Open.Enabled = false;
				this.tlsMain_Open.Enabled = false;
			}

			this.logItemView.DisplayItemDetail(null);
			this.logAttachView.ClearAttachment();

			if (null != this.logViewDoc)
				this.logViewDoc.Reader = this.logReader;
		}
		private void logViewDoc_Initialized(object sender, LogViewerInitializedEventArgs e)
		{
			if (e.Success)
			{
				this.SetEnabled();
			}
			else
			{
				if (this.activeDoc.Text == this.logViewDoc.Text)
				{
					this.SetDisabled();
					MessageBox.Show(e.Failure.Message, "Exceptions Encountered", MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}
		}
		#endregion

		#region Methods
		private bool InitializeUI()
		{
			if (this.logReader.LogConfig.LogType == EventLogType.Machine)
			{
				#region Machine Log
				if (string.IsNullOrEmpty(cmdLineFile))
				{
					Process.Start("eventvwr");
					return false;
				}
				else
				{
					this.logAttachView = new LogAttachmentViewer();
					this.logAttachView.VisibleChanged += new EventHandler(detail_VisibleChanged);
					this.logAttachView.Show(this.dockPanel, HSS.Forms.Docking.DockState.DockBottom);

					string docName = Path.GetFileName(cmdLineFile);
					LogViewerListView saveLog1 = new LogViewerListView();
					saveLog1.Text = docName;
					saveLog1.TabText = docName;
					saveLog1.ToolTipText = cmdLineFile;
					saveLog1.SelectionChanged += new EventHandler<SelectedItemEventArgs>(listView_SelectionChanged);
					saveLog1.FileName = cmdLineFile;
					saveLog1.Show(this.dockPanel, HSS.Forms.Docking.DockState.Document);
					this.activeDoc = saveLog1;
					this.SetEnabled();
				}
				#endregion
			}
			else
			{
				#region Database Log

				this.logAttachView = new LogAttachmentViewer();
				this.logItemView = new LogItemViewer();

				this.logItemView.VisibleChanged += new EventHandler(detail_VisibleChanged);
				this.logItemView.Show(this.dockPanel);

				this.logAttachView.VisibleChanged += new EventHandler(detail_VisibleChanged);
				this.logAttachView.Show(this.dockPanel);

				this.logItemView.Activate();

				if (!string.IsNullOrEmpty(cmdLineFile))
				{
					try
					{
						string docName = Path.GetFileName(cmdLineFile);
						if (File.Exists(cmdLineFile))
						{
							LogViewerListView saveLog1 = new LogViewerListView();
							saveLog1.Text = docName;
							saveLog1.TabText = docName;
							saveLog1.ToolTipText = cmdLineFile;
							saveLog1.SelectionChanged += new EventHandler<SelectedItemEventArgs>(listView_SelectionChanged);
							saveLog1.FileName = cmdLineFile;
							saveLog1.Show(this.dockPanel, HSS.Forms.Docking.DockState.Document);
							this.activeDoc = saveLog1;
							this.SetEnabled();
							return true;
						}
					}
					catch { }
				}

				this.logViewDoc = new LogViewerListView();
				this.logViewDoc.Text = currentLog;
				this.logViewDoc.TabText = currentLog;
				this.logViewDoc.FormClosing += new FormClosingEventHandler(listView_FormClosing);
				this.logViewDoc.SelectionChanged += new EventHandler<SelectedItemEventArgs>(listView_SelectionChanged);
				this.logViewDoc.ItemDoubleClicked += new EventHandler<SelectedItemEventArgs>(logViewDoc_ItemDoubleClicked);
				this.logViewDoc.Initialized += new EventHandler<LogViewerInitializedEventArgs>(logViewDoc_Initialized);
				this.logViewDoc.AutoLoadReader = true;
				this.logViewDoc.Show(this.dockPanel, HSS.Forms.Docking.DockState.Document);
				this.activeDoc = this.logViewDoc;
				this.SetEnabled();

				#endregion
			}

			this.dockPanel.ActiveDocumentChanged += new System.EventHandler(this.dockPanel_ActiveDocumentChanged);

			return true;

		}
		private void RefreshData()
		{
			#region Reset find criteria
			this.tlsMain_FindNext.Enabled = false;
			#endregion

			this.SetEnabled();

			if (activeDoc.RefreshLog())
			{
				this.SetEnabled();
			}
			else
			{
				this.mnuLog_SaveAs.Enabled = false;
				this.mnuLog_SaveSelected.Enabled = false;
				this.tlsMain_SaveAs.Enabled = false;
				this.tlsMain_Find.Enabled = false;
			}
		}
		private void OpenLogFile()
		{
			// Browse file...
			using (OpenFileDialog f = new OpenFileDialog())
			{
				f.Filter = "HSS Log Xml File (*.hsslx)|*.hsslx|HSS Log Binary File (*.hsslb)|*.hsslb";
				f.DefaultExt = ".xml";
				if (f.ShowDialog(this) == DialogResult.OK)
				{
					string docName = Path.GetFileName(f.FileName);
					if (this.dockPanel.DocumentExists(docName))
					{
						MessageBox.Show("This file is already opened. Please select a different file.", "Open Log File", MessageBoxButtons.OK, MessageBoxIcon.Warning);
						return;
					}
					else
					{
						LogViewerListView saveLog1 = new LogViewerListView();
						saveLog1.Name = docName;
						saveLog1.Text = docName;
						saveLog1.TabText = docName;
						saveLog1.ToolTipText = f.FileName;
						saveLog1.SelectionChanged += new EventHandler<SelectedItemEventArgs>(listView_SelectionChanged);
						saveLog1.FileName = f.FileName;
						saveLog1.Show(this.dockPanel, HSS.Forms.Docking.DockState.Document);
					}
				}
			}
		}
		private void SaveLog()
		{
			activeDoc.SaveLog();
		}
		private void SaveSelectedItems()
		{
			activeDoc.SaveSelectedEntries();
		}
		private void ClearLog()
		{
			InputBoxResult res = InputBox.Show("Enter the number of days to retain", "Truncate Log", "30", null);
			if (res.OK && !string.IsNullOrEmpty(res.Text))
			{
				this.logReader.ClearLog(int.Parse(res.Text));
				this.RefreshData();
			}
		}
		private void FindInList(string SearchText)
		{
			if (!string.IsNullOrEmpty(SearchText))
			{

				bool found = activeDoc.FindInList(SearchText);

				if (found)
				{
					this.tlsMain_FindNext.Enabled = true;
				}
				else
				{
					this.tlsMain_FindNext.Enabled = false;
					string msg = "No items found containing the text [ " + SearchText + " ]";
					MessageBox.Show(msg, "Search", MessageBoxButtons.OK, MessageBoxIcon.Information);
				}
			}
			else
			{
				this.tlsMain_FindNext.Enabled = false;
			}
		}
		private void FindNextInList()
		{
			bool found = activeDoc.FindNextInList();

			if (found)
			{
				this.tlsMain_FindNext.Enabled = true;
			}
			else
			{
				this.tlsMain_FindNext.Enabled = false;
				string msg = "No more items found.";
				MessageBox.Show(msg, "Search", MessageBoxButtons.OK, MessageBoxIcon.Information);
			}
		}
		private void ShowFilter()
		{
			activeDoc.FilterVisible = this.tlsMain_Filter.Checked;
		}
		private void ShowDetails()
		{
			if (this.tlsMain_Properties.Checked)
			{
				this.logAttachView.Show();
				this.logItemView.Show();
			}
			else
			{
				this.logItemView.Hide();
				this.logAttachView.Hide();
			}
		}
		private void ShowAboutDialog()
		{
			// Show About Dialog
			new LogViewerAbout().ShowDialog(this);
		}
		private void SetDetail(LogEntry entry)
		{

			this.logItemView.DisplayItemDetail(entry);

			if (null == entry)
			{
				this.logAttachView.ClearAttachment();
				return;
			}

			if (entry.AttachmentId > 0)
			{
				if (this.logReader.LogConfig.LogType == EventLogType.Machine)
				{
					Exception ex = new Exception("Cannot retrieve attachment. Logging not configured for data access.");
					ex.Source = "LogViewer.DisplayAttachment()";
					this.logAttachView.DisplayException(ex);
				}
				else
				{
					try
					{
						this.logAttachView.DisplayDownloading();
						this.logReader.BeginGetAttachment(new AsyncCallback(this.GetAttachmentAsyncCompleted), entry.AttachmentId);
					}
					catch (Exception ex)
					{
						Trace.WriteLine(ex.ToString());
						this.logAttachView.ClearAttachment();
					}
				}
			}
			else
			{
				this.logAttachView.ClearAttachment();
			}
		}
		private void SetEnabled()
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new MethodInvoker(this.SetEnabled));
				return;
			}

			this.mnuLog_Open.Enabled = true;
			this.tlsMain_Open.Enabled = true;

			this.tlsMain_FindNext.Enabled = false;

			bool curLog = (activeDoc.TabText == currentLog);

			this.mnuLog_SaveAs.Enabled = curLog;
			this.mnuLog_SaveSelected.Enabled = curLog;
			this.mnuLog_Clear.Enabled = curLog;
			this.mnuLog_Close.Enabled = !curLog;
			this.mnuView_Filter.Enabled = true;
			this.mnuView_Detail.Enabled = true;
			this.mnuView_Refresh.Enabled = true;

			this.tlsMain_SaveAs.Enabled = curLog;
			this.tlsMain_Filter.Enabled = true;
			this.tlsMain_Refresh.Enabled = true;
			this.tlsMain_Properties.Enabled = true;
			this.tlsMain_Find.Enabled = true;
			this.tlsMain_FindText.Enabled = true;
			this.tlsMain_FindNext.Enabled = true;

			this.mnuView_Filter.Checked = activeDoc.FilterVisible;
			this.tlsMain_Filter.Checked = activeDoc.FilterVisible;

		}
		private void SetDisabled()
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new MethodInvoker(this.SetDisabled));
				return;
			}

			this.mnuLog_Open.Enabled = true;
			this.tlsMain_Open.Enabled = true;

			this.mnuLog_SaveAs.Enabled = false;
			this.mnuLog_SaveSelected.Enabled = false;
			this.mnuLog_Clear.Enabled = false;
			this.mnuLog_Close.Enabled = false;
			this.mnuView_Filter.Enabled = false;
			this.mnuView_Refresh.Enabled = false;

			this.tlsMain_SaveAs.Enabled = false;
			this.tlsMain_Filter.Enabled = false;
			this.tlsMain_Refresh.Enabled = false;
			this.tlsMain_Find.Enabled = false;
			this.tlsMain_FindText.Enabled = false;
			this.tlsMain_FindNext.Enabled = false;

		}
		private void GetAttachmentAsyncCompleted(IAsyncResult Result)
		{
			try
			{
				LogEntryAttachment attachment = SqlLogReader.EndGetAttachment(Result);
				this.logAttachView.DisplayAttachment(attachment);
			}
			catch (Exception ex)
			{
				this.logAttachView.DisplayException(ex);
			}
		}
		/// <summary>
		/// Raises the System.Windows.Forms.Form.Closing event
		/// </summary>
		/// <param name="e">A System.ComponentModel.CancelEventArgs that contains the event data</param>
		protected override void OnClosing(CancelEventArgs e)
		{
			this.dockPanel.ActiveDocumentChanged -= new System.EventHandler(this.dockPanel_ActiveDocumentChanged);
			base.OnClosing(e);
		}
		#endregion

		#region Event Handlers

		#region Menu
		private void mnuLog_Open_Click(object sender, EventArgs e)
		{
			this.OpenLogFile();
		}
		private void mnuLog_SaveAs_Click(object sender, EventArgs e)
		{
			this.SaveLog();
		}
		private void mnuLog_SaveSelected_Click(object sender, EventArgs e)
		{
			this.SaveSelectedItems();
		}
		private void mnuLog_Clear_Click(object sender, EventArgs e)
		{
			this.ClearLog();
		}
		private void mnuLog_Close_Click(object sender, EventArgs e)
		{
			activeDoc.Close();
		}
		private void mnuLog_Exit_Click(object sender, EventArgs e)
		{
			this.Close();
		}
		private void mnuView_Detail_Click(object sender, EventArgs e)
		{
			this.tlsMain_Properties.Checked = this.mnuView_Detail.Checked;
			this.ShowDetails();
		}
		private void mnuView_Filter_Click(object sender, EventArgs e)
		{
			this.tlsMain_Filter.Checked = this.mnuView_Filter.Checked;
			this.ShowFilter();
		}
		private void mnuView_Refresh_Click(object sender, EventArgs e)
		{
			this.RefreshData();
		}
		private void mnuHelp_About_Click(object sender, EventArgs e)
		{
			this.ShowAboutDialog();
		}
		#endregion

		#region Toolbar

		private void tlsMain_Open_Click(object sender, EventArgs e)
		{
			this.OpenLogFile();
		}
		private void tlsMain_SaveAs_Click(object sender, EventArgs e)
		{
			this.SaveLog();
		}
		private void tlsMain_Properties_Click(object sender, EventArgs e)
		{
			this.mnuView_Detail.Checked = this.tlsMain_Properties.Checked;
			this.ShowDetails();
		}
		private void tlsMain_Filter_Click(object sender, EventArgs e)
		{
			this.mnuView_Filter.Checked = this.tlsMain_Filter.Checked;
			this.ShowFilter();
		}
		private void tlsMain_Refresh_Click(object sender, EventArgs e)
		{
			this.RefreshData();
		}
		private void tlsMain_Find_Click(object sender, EventArgs e)
		{
			string prompt = "Enter the text to search for";
			string title = "Search";
			InputDialogResult res = InputDialog.Show(prompt, title, this.tlsMain_FindText.Text, null);
			if (res.OK)
			{
				if (!this.tlsMain_FindText.Items.Contains(res.Text))
				{
					this.tlsMain_FindText.Items.Add(res.Text);
					this.tlsMain_FindText.SelectedItem = res.Text;
				}
				else
				{
					this.FindInList(this.tlsMain_FindText.Text);
				}
			}
		}
		private void tlsMain_FindText_SelectedIndexChanged(object sender, EventArgs e)
		{
			this.FindInList(this.tlsMain_FindText.Text);
		}
		private void tlsMain_FindText_KeyPress(object sender, KeyPressEventArgs e)
		{
			if (e.KeyChar == (char)13)
				this.FindInList(tlsMain_FindText.Text);
		}
		private void tlsMain_FindNext_Click(object sender, EventArgs e)
		{
			this.FindNextInList();
		}

		#endregion

		void listView_SelectionChanged(object sender, SelectedItemEventArgs e)
		{
			this.SetDetail(e.Entry);
		}
		void logViewDoc_ItemDoubleClicked(object sender, SelectedItemEventArgs e)
		{
			if (!this.mnuView_Detail.Checked)
			{
				this.mnuView_Detail.Checked = true;
				this.tlsMain_Properties.Checked = true;
				this.ShowDetails();
			}
		}
		void listView_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (e.CloseReason == CloseReason.UserClosing)
				e.Cancel = true;
		}
		void detail_VisibleChanged(object sender, EventArgs e)
		{
			this.mnuView_Detail.Checked = this.logItemView.Visible;
			this.tlsMain_Properties.Checked = this.logItemView.Visible;
		}
		void dockPanel_ActiveDocumentChanged(object sender, EventArgs e)
		{
			if (null != this.dockPanel.ActiveDocument)
				activeDoc = (LogViewerListView)this.dockPanel.ActiveDocument;

			if (null == this.dockPanel.ActiveDocument)
			{
				this.SetDisabled();
				this.mnuView_Detail.Enabled = false;
				this.tlsMain_Properties.Enabled = false;
				this.logAttachView.Hide();
				this.logItemView.Hide();
				return;
			}

			if (activeDoc.IsInitialized)
				this.SetEnabled();
			else
				this.SetDisabled();
		}

		#endregion
	}
	#endregion
}